<template>
    <div id="relation" class="network">
        <svg ref="svg" width="1200px" height="1000px"></svg>
    </div>
</template>

<script>
import * as d3 from "d3";
import dataion from '@/assets/json/杜甫人物关系分类3.json';

export default {
    name: "Relation",
    data() {
        return {
            data: dataion,
            simulation: null // 添加 simulation 属性
        };
    },

    mounted() {
        this.createSvg();
    },

    methods: {
        createSvg() {
            const svg = d3.select(this.$refs.svg);
            const width = +svg.attr("width");
            const height = +svg.attr("height");
            let centerNodes = [];
            let duFuNode = this.data.nodes.find(node => node.id === '杜甫');
            const groupSet = new Set(this.data.nodes.map(node => node.group));
            groupSet.forEach(group => {
                // 创建中心结点
                let centerNode = { id: `关系-${group}`, group, x: width / 2, y: height / 2 };
                centerNodes.push(centerNode);
                this.data.nodes.push(centerNode);
                // 将杜甫连接到中心节点
                this.data.links.push({ source: duFuNode, target: centerNode });
            });
            //const groupCount = new Set(this.data.nodes.map(node => node.group)).size;
            //const angleStep = 2 * Math.PI / groupCount;
            //const radius = width / 6; // 假设每个 group 之间的距离为 width 的六分之一

            const groupCenters = {};
            this.data.nodes.forEach(node => {
                if (!node.id.startsWith('center-')) { // 排除中心节点
                    let centerNode = centerNodes.find(cn => cn.group === node.group);
                    if (centerNode) {
                        this.data.links.push({ source: centerNode, target: node });
                    }
                }
            });
            // this.data.nodes.forEach(node => {

            //   //console.log(d => groupCenters[d.group].x)
            //   if (!groupCenters[node.group]) {
            //     const angle = node.group * angleStep - Math.PI; // 从垂直向上开始
            //     groupCenters[node.group] = {
            //       x: width / 3 + Math.cos(angle) * radius ,
            //       y: height + Math.sin(angle) * radius
            //     };
            //   }

            //   if (node.id === '杜甫') {
            //     node.fx = width / 2;
            //     node.fy = height / 2;
            //   } 

            // });

            this.simulation = d3.forceSimulation(this.data.nodes)
                .force("link", d3.forceLink(this.data.links).id(d => d.id).distance(100))
                .force("charge", d3.forceManyBody().strength(-300))
                .force("center", d3.forceCenter(width / 2, height / 2))
                .on("tick", () => this.ticked(svg.selectAll(".link"), svg.selectAll(".node"), svg.selectAll(".node-text")));

            // .force("x", d3.forceX().x(d => groupCenters[d.group].x))
            // .force("y", d3.forceY().y(d => groupCenters[d.group].y));

            ;
            // Object.keys(groupCenters).forEach(group => {
            //   this.simulation.force("x", d3.forceX(groupCenters[group].x).strength(0.1));
            //   this.simulation.force("y", d3.forceY(groupCenters[group].y).strength(0.1));
            // });
            //this.simulation.nodes(this.data.nodes);
            this.simulation.force("link").links(this.data.links);
            // this.simulation.force("x", d3.forceX((d) => {
            //   return d.group === 6 ? width * 1 / 8 : width / 2; // 如果是 group 6，则推向左侧
            // }).strength(0.5)); // 力的强度可以根据需要调整
            // centerNodes.forEach(centerNode => {
            //   this.simulation.force("x", d3.forceX(centerNode.x).strength(0.1));
            //   this.simulation.force("y", d3.forceY(centerNode.y).strength(0.1));
            // });

            const link = svg.append("g")
                .attr("class", "links")
                .selectAll("line")
                .data(this.data.links)
                .enter().append("line")
                .attr("stroke", "#989")
                .attr("stroke-opacity", 0.5) // 增加透明度
                .attr("stroke-width", 4) // 增加线宽
                ;
            const nodeGroup = svg.append("g")
                .attr("class", "nodes");
            const groupColorMap = {
                '1': '#d9534f',        // 例如组 '1' 显示浅红色
                '3': '#fde74c',        // 组 '3' 显示浅橙色
                '6': '#5bc0de',       // 组 '6' 显示浅蓝色
                '7': '#9bc5de',       // 组 '7' 显示浅紫色
            };

            const node = nodeGroup.selectAll("circle")
                .data(this.data.nodes)
                .enter().append("circle")
                .attr("r", d => (d.id === '杜甫' ? 40 : 20)) // 杜甫的节点更大
                .attr("fill", d => groupColorMap[d.group] || '#d3d3d3')
                .call(d3.drag()
                    .on("start", this.dragstarted)
                    .on("drag", this.dragged)
                    .on("end", this.dragended));

            node.append("title")
                .text(d => d.id);
            // 添加文本标签
            nodeGroup.selectAll("text")
                .data(this.data.nodes)
                .enter().append("text")
                .attr("class", "node-text") // 添加类名便于后续操作  
                .text(d => d.id) // 假设node中有name属性
                .attr("font-size", 14)
                .attr("text-anchor", "middle") // 文本锚点设为中间  
                .attr("dy", ".35em") // 调整文本的垂直位置，.35em大约为文本高度的一半  
                .attr("x", d => d.x) // 假设你的节点数据中有x坐标  
                .attr("y", d => d.y); // 假设你的节点数据中有y坐标
            // 假设圆圈的选择代码如下  
            //   this.simulation
            //     .force("link")
            //     .links(this.data.links);
            // },
            this.simulation
                .on("tick", () => this.ticked(link, node));
            this.simulation.alpha(1).restart();
            this.simulation.force("link")
                .links(this.data.links);
        },

        ticked(link, node) {
            link
                .attr("x1", d => d.source.x)
                .attr("y1", d => d.source.y)
                .attr("x2", d => d.target.x)
                .attr("y2", d => d.target.y);

            node
                .attr("cx", d => d.x)
                .attr("cy", d => d.y);

            // 更新文本位置
            d3.selectAll("text.node-text")
                .attr("x", d => d.x + 7) // 文字横向位置基于节点偏移
                .attr("y", d => d.y + 3); // 文字纵向位置基于节点偏移
        },

        dragstarted(event, d) {
            if (!event.active) this.simulation.alphaTarget(0.3).restart();
            d.fx = d.x;
            d.fy = d.y;
        },

        dragged(event, d) {
            d.fx = event.x;
            d.fy = event.y;
        },

        dragended(event, d) {
            if (!event.active) this.simulation.alphaTarget(0);
            d.fx = null;
            d.fy = null;
        }
    }
};
</script>

<style>
#relation {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    font-family: 'Arial', sans-serif;

}

.link.inactive,
.linetext.inactive,
.node.inactive image,
.node.inactive text {
    opacity: .2;
}

.tooltip {
    font-family: "KaiTi", "serif";
    font-size: 12px;
    width: 220px;
    height: auto;
    position: absolute;
    background: #fff;
    opacity: 0.5;
    border-radius: 5px;
    box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
}

.tooltip .title {
    color: #fff;
    padding: 5px;
    font-size: 14px;
    background-color: #d2a36c;
    border-radius: 5px 5px 0 0;
}

.tooltip .detail-info {
    width: 100%;
    border-collapse: collapse;
    border: 1px solid #d2a36c;
}

.tooltip .detail-info td {
    padding: 3px 5px;
    color: #666;
    vertical-align: middle;
}

.tooltip .detail-info tr:nth-of-type(odd) {
    background: #f9f9f9;
}

.tooltip .detail-info td.td-label {
    color: #333;
    width: 60px;
}

.tooltip .detail-info td a {
    color: #666
}
</style>